home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2010 April / PCWorld0410.iso / hity wydania / Ubuntu 9.10 PL / karmelkowy-koliberek-desktop-9.10-i386-PL.iso / casper / filesystem.squashfs / usr / share / ibus-table / engine / tabcreatedb.py < prev    next >
Text File  |  2009-07-30  |  11KB  |  298 lines

  1. #!/usr/bin/python
  2. # -*- coding: utf-8 -*-
  3. # vim: set et sts=4 sw=4
  4. #
  5. # ibus-table - The Tables engine for IBus
  6. #
  7. # Copyright (c) 2008-2009 Yu Yuwei <acevery@gmail.com>
  8. #
  9. # This library is free software; you can redistribute it and/or
  10. # modify it under the terms of the GNU Lesser General Public
  11. # License as published by the Free Software Foundation; either
  12. # version 2.1 of the License, or (at your option) any later version.
  13. #
  14. # This library is distributed in the hope that it will be useful,
  15. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  17. # Lesser General Public License for more details.
  18. #
  19. # You should have received a copy of the GNU Lesser General Public
  20. # License along with this library; if not, write to the Free Software
  21. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  22. #
  23. # $Id: $
  24. #
  25.  
  26. import os
  27. import sys
  28. sys.path.append( os.path.dirname(os.path.abspath(__file__)) )
  29. import tabsqlitedb
  30. import bz2
  31. import re
  32.  
  33. from optparse import OptionParser
  34. # we use OptionParser to parse the cmd arguments :)
  35. opt_parser = OptionParser()
  36.  
  37. opt_parser.add_option( '-n', '--name',
  38.         action = 'store', dest='name',default = None,
  39.         help = 'set the database name we will use, default is %default')
  40.  
  41. opt_parser.add_option( '-s', '--source',
  42.         action = 'store', dest='source', default = 'xingma.txt.bz2',
  43.         help = 'tell me which file is the source file of IME, default is %default')
  44.  
  45. opt_parser.add_option( '-e', '--extra',
  46.         action = 'store', dest='extra', default = '',
  47.         help = 'tell me which file is the extra words file for IME, default is %default')
  48.  
  49. opt_parser.add_option( '-p', '--pinyin',
  50.         action = 'store', dest='pinyin', default = '/usr/share/ibus-table/data/pinyin_table.txt.bz2',
  51.         help = 'tell me which file is the source file of pinyin, default is %default')
  52.  
  53. opt_parser.add_option( '-o', '--no-create-index',
  54.         action = 'store_false', dest='index', default = True,
  55.         help = 'do not create index on database, only for distrubution purpose, normal user should not invoke this flag!')
  56.  
  57. opt_parser.add_option( '-i', '--create-index-only',
  58.         action = 'store_true', dest='only_index', default = False,
  59.         help = 'only create index on exist database')
  60.  
  61. opt_parser.add_option( '-d', '--debug',
  62.         action = 'store_true', dest='debug', default = False,
  63.         help = 'print extra debug messages')
  64.  
  65.  
  66.  
  67. opts,args = opt_parser.parse_args()
  68. if not opts.name and opts.only_index:
  69.     print 'Please give me the database you want to create index on'
  70.     sys.exit(2)
  71.  
  72. if not opts.name:
  73.     opts.name = os.path.basename(opts.source).split('.')[0] + '.db'
  74.  
  75.  
  76. def main ():
  77.     def debug_print ( message ):
  78.         if opts.debug:
  79.             print message
  80.     
  81.     if not opts.only_index:
  82.         try:
  83.             os.unlink (opts.name)
  84.         except:
  85.             pass
  86.     
  87.     debug_print ("Processing Database")
  88.     db = tabsqlitedb.tabsqlitedb ( filename = opts.name)
  89.     #db.db.execute( 'PRAGMA synchronous = FULL; ' )
  90.     
  91.     def parse_source (f):
  92.         _attri = []
  93.         _table = []
  94.         _gouci = []
  95.         patt_com = re.compile(r'^###.*')
  96.         patt_blank = re.compile(r'^[ \t]*$')
  97.         patt_conf = re.compile(r'.*=.*')
  98.         patt_table = re.compile(r'(.*)\t(.*)\t.*')
  99.         patt_gouci = re.compile(r'.*\t.*')
  100.         patt_s = re.compile(r'(.*)\t([\x00-\xff]{3})\t.*')
  101.  
  102.         for l in f:
  103.             if ( not patt_com.match(l) ) and ( not patt_blank.match(l) ):
  104.                 for _patt, _list in ( (patt_conf,_attri),(patt_table,_table),(patt_gouci,_gouci) ):
  105.                     if _patt.match(l):
  106.                         _list.append(l)
  107.                         break
  108.         if not _gouci:
  109.             #user didn't provide goucima, so we use the longest single character encode as the goucima.
  110.             gouci_dict = {}
  111.             for line in _table:
  112.                 res = patt_s.match(line)
  113.                 if res:
  114.                     if gouci_dict.has_key(res.group(2)):
  115.                         if len(res.group(1)) > len(gouci_dict[res.group(2)]):
  116.                             gouci_dict[res.group(2)] = res.group(1)
  117.                     else:
  118.                         gouci_dict[res.group(2)] = res.group(1)
  119.             for key in gouci_dict:
  120.                 _gouci.append('%s\t%s' %(key,gouci_dict[key] ) )
  121.             _gouci.sort()
  122.  
  123.         return (_attri, _table, _gouci)
  124.  
  125.     def parse_pinyin (f):
  126.         _pinyins = []
  127.         patt_com = re.compile(r'^#.*')
  128.         patt_blank = re.compile(r'^[ \t]*$')
  129.         patt_py = re.compile(r'(.*)\t(.*)\t(.*)')
  130.         patt_yin = re.compile(r'[a-z]+[1-5]')
  131.  
  132.         for l in f:
  133.             if ( not patt_com.match(l) ) and ( not patt_blank.match(l) ):
  134.                 res = patt_py.match(l)
  135.                 if res:
  136.                     yins = patt_yin.findall(res.group(2))
  137.                     for yin in yins:
  138.                         _pinyins.append("%s\t%s\t%s" \
  139.                                 % (res.group(1), yin, res.group(3)))
  140.         return _pinyins[:]
  141.     
  142.     def parse_extra (f):
  143.         _extra = []
  144.         patt_com = re.compile(r'^###.*')
  145.         patt_blank = re.compile(r'^[ \t]*$')
  146.         patt_extra = re.compile(r'(.*)\t(.*)')
  147.         patt_s = re.compile(r'(.*)\t([\x00-\xff]{3})\t.*')
  148.         
  149.         for l in f:
  150.             if ( not patt_com.match(l) ) and ( not patt_blank.match(l) ):
  151.                 if patt_extra.match(l):
  152.                     _extra.append(l)
  153.         
  154.         return _extra
  155.     
  156.     def pinyin_parser (f):
  157.         for py in f:
  158.             _zi, _pinyin, _freq = unicode (py,'utf-8').strip ().split()
  159.             yield (_pinyin, _zi, _freq)
  160.  
  161.     def phrase_parser (f):
  162.         list=[]
  163.         for l in f:
  164.             xingma, phrase, freq = unicode (l, "utf-8").strip ().split ('\t')
  165.             list.append ( (xingma, phrase, int(freq), 0) )
  166.         return list
  167.  
  168.     def goucima_parser (f):
  169.         for l in f:
  170.             zi,gcm = unicode (l, "utf-8").strip ().split ()
  171.             yield (zi, gcm)
  172.     
  173.     def attribute_parser (f):
  174.         for l in f:
  175.             try:
  176.                 attr,val = unicode (l,"utf-8").strip().split ('=')
  177.             except:
  178.                 attr,val = unicode (l,"utf-8").strip().split ('==')
  179.             attr = attr.strip()
  180.             origin_attr = attr
  181.             attr = attr.lower()
  182.             val = val.strip()
  183.             yield (attr,val)
  184.     
  185.     def extra_parser (f):
  186.         list = []
  187.         for l in f:
  188.             phrase, freq = unicode (l, "utf-8").strip ().split ()
  189.             try:
  190.                 _tabkey = db.parse_phrase_to_tabkeys(phrase)
  191.                 list.append( (_tabkey,phrase,freq,0) )
  192.             except:
  193.                 print '\"%s\" would not been added' % phrase.encode('utf-8')
  194.         return list
  195.  
  196.     if opts.only_index:
  197.         debug_print ('Only create Indexes')
  198.         debug_print ( "Optimizing database " )
  199.         db.optimize_database ()
  200.     
  201.         debug_print ('Create Indexes ')
  202.         db.create_indexes ('main')
  203.         debug_print ('Done! :D')
  204.         return 0
  205.  
  206.     # now we parse the ime source file
  207.     debug_print ("\tLoad sources \"%s\"" % opts.source)
  208.     patt_s = re.compile( r'.*\.bz2' )
  209.     _bz2s = patt_s.match(opts.source)
  210.     if _bz2s:
  211.         source = bz2.BZ2File ( opts.source, "r" )
  212.     else:
  213.         source = file ( opts.source, 'r' )
  214.     # first get config line and table line and goucima line respectively
  215.     debug_print ('\tParsing table source file ')
  216.     attri,table,gouci =  parse_source ( source )
  217.     
  218.     debug_print ('\t  get attribute of IME :)')
  219.     attributes = attribute_parser ( attri )
  220.     debug_print ('\t  add attributes into DB ')
  221.     db.update_ime ( attributes )
  222.     db.create_tables ('main')
  223.  
  224.     # second, we use generators for database generating:
  225.     debug_print ('\t  get phrases of IME :)')
  226.     phrases = phrase_parser ( table)
  227.     
  228.     # now we add things into db
  229.     debug_print ('\t  add phrases into DB ')
  230.     db.add_phrases ( phrases )
  231.     
  232.     if db.get_ime_property ('user_can_define_phrase').lower() == u'true':
  233.         debug_print ('\t  get goucima of IME :)')
  234.         goucima = goucima_parser (gouci)
  235.         debug_print ('\t  add goucima into DB ')
  236.         db.add_goucima ( goucima )
  237.     
  238.     if db.get_ime_property ('pinyin_mode').lower() == u'true':
  239.         debug_print ('\tLoad pinyin source \"%s\"' % opts.pinyin)
  240.         _bz2p = patt_s.match(opts.pinyin)
  241.         if _bz2p:
  242.             pinyin_s = bz2.BZ2File ( opts.pinyin, "r" )
  243.         else:
  244.             pinyin_s = file ( opts.pinyin, 'r' )
  245.         debug_print ('\tParsing pinyin source file ')
  246.         pyline = parse_pinyin (pinyin_s)
  247.         debug_print ('\tPreapring pinyin entries')
  248.         pinyin = pinyin_parser (pyline)
  249.         debug_print ('\t  add pinyin into DB ')
  250.         db.add_pinyin ( pinyin )
  251.  
  252.     debug_print ("Optimizing database ")
  253.     db.optimize_database ()
  254.     
  255.     if db.get_ime_property ('user_can_define_phrase').lower() == u'true' and opts.extra:
  256.         debug_print( '\tPreparing for adding extra words' )
  257.         db.create_indexes ('main')
  258.         debug_print ('\tLoad extra words source \"%s\"' % opts.extra)
  259.         _bz2p = patt_s.match(opts.extra)
  260.         if _bz2p:
  261.             extra_s = bz2.BZ2File ( opts.extra, "r" )
  262.         else:
  263.             extra_s = file ( opts.extra, 'r' )
  264.         debug_print ('\tParsing extra words source file ')
  265.         extraline = parse_extra (extra_s)
  266.         debug_print ('\tPreparing extra words lines')
  267.         db.cache_goucima()
  268.         debug_print ('\t  Goucima has been cache to memory')
  269.         extrawds = extra_parser (extraline)
  270.         debug_print( '\t  we have %d extra phrases from source' % len(extrawds))
  271.         # first get the entry of original phrases from
  272.         # phrases-[(xingma, phrase, int(freq), 0)]
  273.         orig_phrases = {}
  274.         map (lambda x: orig_phrases.update({"%s\t%s"%(x[0],x[1]):x}), phrases )
  275.         debug_print( '\t  the len of orig_phrases is: %d' % len(orig_phrases) )
  276.         extra_phrases = {}
  277.         map (lambda x: extra_phrases.update({"%s\t%s" %(x[0],x[1]):x}), extrawds )
  278.         debug_print ( '\t  the len of extra_phrases is: %d' % len(extra_phrases) )
  279.         # pop duplicated keys
  280.         map (lambda x: extra_phrases.pop(x) if orig_phrases.has_key(x) else 0, extra_phrases.keys() )
  281.         debug_print( '\t  %d extra phrases will be added' % len(extra_phrases))
  282.         new_phrases = extra_phrases.values()
  283.         debug_print ('\tAdding extra words into DB ')
  284.         db.add_phrases (new_phrases)
  285.         debug_print ("Optimizing database ")
  286.         db.optimize_database ()
  287.     
  288.     if opts.index:
  289.         debug_print ('Create Indexes ')
  290.         db.create_indexes ('main')
  291.     else:
  292.         debug_print ("We don't create index on database, you should only active this function only for distribution purpose")
  293.         db.drop_indexes ('main')
  294.     debug_print ('Done! :D')
  295.     
  296. if __name__ == "__main__":
  297.     main ()
  298.